package osami.communication;

import java.io.IOException;

import javax.bluetooth.DataElement;
import javax.bluetooth.LocalDevice;
import javax.bluetooth.RemoteDevice;
import javax.bluetooth.ServiceRecord;
import javax.bluetooth.ServiceRegistrationException;
import javax.bluetooth.UUID;
import javax.microedition.io.Connector;
import javax.microedition.io.StreamConnection;
import javax.microedition.io.StreamConnectionNotifier;


/**
 * BluetoothConnectionListener listens to incoming bluetooth connections and
 * creates new connection objects for connecting clients
 * 
 * @author osami
 *
 */
public class BluetoothConnectionListener implements ConnectionListener
{
	private Activator iEngine;
	private CommServer iCommServer;
	private StreamConnectionNotifier iStreamConnNotifier = null;
	private Thread iListenerThread = null;
	private ServiceRecord origRecord = null;
	private boolean running = true;
	
	
	/**
	 * Default constructor
	 * 
	 * @param aCommServer
	 * @throws IOException
	 */
	public BluetoothConnectionListener( Activator aEngine, CommServer aCommServer ) throws IOException
	{
		iEngine = aEngine;
		iCommServer = aCommServer;
		
		initialize();
		
		// Create and start a thread in which the listener runs
		iListenerThread = new Thread( this );
		iListenerThread.start();
	}
	
	
	/**
	 * Initializes the listener. ServiceRecord is altered to meat our needs by setting service provider name to OSAMI.
	 * This manipulation differentiates OSAMI node from different/regular SPP servers, so OSAMI will not connect to unnecessary bluetooth nodes.
	 * @throws IOException
	 */
	private void initialize() throws IOException
	{
		//Create a UUID for SPP
		UUID uuid = new UUID( "1101", true );

		//Create the service url
		String connectionString = "btspp://localhost:" + uuid +";name=OSAMI";

		//Open server url
		iStreamConnNotifier = (StreamConnectionNotifier)Connector.open( connectionString );

		System.out.println( "BluetoothConnectionListener.initialize: Server Started. Waiting for clients to connect...");

		LocalDevice localDevice = LocalDevice.getLocalDevice();
		System.out.println( "BluetoothConnectionListener.initialize: Local BT address: " + localDevice.getBluetoothAddress() );
		
		
        /* Get the ServiceRecord associated with the notifier */
		ServiceRecord record = null;
        try 
        {
        	record = localDevice.getRecord( iStreamConnNotifier );
        	//Original serviceRecord is kept in safe. It will be written back to its initial state when stopping OSAMI.
        	origRecord = record;
            DataElement elm = null;
            
            //Set service description... OSAMI bluetooth server
            elm = new DataElement( DataElement.STRING, "OSAMI BT SPP SERVER" );
            record.setAttributeValue( 0x100, elm );
            
            //Set service provider name to OSAMI -> now we can parse connections that have OSAMI as provider name
            elm = new DataElement( DataElement.STRING, "OSAMI" );
            record.setAttributeValue( 0x102, elm );

            //Update the record, else changes are lost
            try
            {
                localDevice.updateRecord( record );
            }
            catch ( ServiceRegistrationException aException )
            {
                aException.printStackTrace();
            }
        }
        catch ( IllegalArgumentException aException )
        {    
            aException.printStackTrace();
        }

        	
        //OK.. Initialization complete
	}
	
	
	/**
	 * Main loop of the listener
	 * 
	 */
	public void run()
	{
		while ( true )
		{
			try
			{
				//Wait for client connection
				if (running)
				{	
				StreamConnection connection = iStreamConnNotifier.acceptAndOpen();
				
				if ( connection != null )
				{
					RemoteDevice dev = RemoteDevice.getRemoteDevice( connection );

					System.out.println( "BTConnectionListener.run: A client from " + dev.getBluetoothAddress() + " has connected!" );
					BluetoothConnection client = new BluetoothConnection( iEngine, iCommServer, dev, connection );
					iCommServer.addClient( client );
					System.out.println( "BTConnectionListener.run: A connection has been established." );
				}
			}
			}
			catch ( IOException aException )
			{
				System.out.println( "BTConnectionListener.run: socket closed");
//				aException.printStackTrace();
			}
		}
	}
	

	/**
	 * Closes the listener and writes the initial serviceRecord data which is very important.
	 * 
	 */
	public void closeConnection()
	{
		System.out.println("BluetoothConnection.closeConnection: clearing ServiceRecord..");
		try
		{
			LocalDevice localDevice = LocalDevice.getLocalDevice();
			localDevice.updateRecord( origRecord );
			
			iStreamConnNotifier.close();
			running = false;
			iListenerThread.notify();
			iListenerThread.interrupt();
	    }
		catch( Exception aException ) 
		{
			//aException.printStackTrace();
			System.out.println("BluetoothConnection.closeConnection: Interrupting thread..");
	    }
	}
}
